package state

/**
二元运算指令
!!! 注意这里的 参数顺序
*/
func _binaryArith(i Instruction, vm LuaVM, op ArithOp) {
	a, b, c := i.ABC()
	a += 1
	vm.GetRK(b)
	vm.GetRK(c)
	vm.Arith(op)
	vm.Replace(a)
}

func _unaryArith(i Instruction, vm LuaVM, op ArithOp) {
	a, b, _ := i.ABC()
	a += 1
	b += 1
	vm.PushValue(b)
	vm.Arith(op)
	vm.Replace(a)
}

func add(i Instruction, vm LuaVM)  { _binaryArith(i, vm, LUA_OPADD) }
func sub(i Instruction, vm LuaVM)  { _binaryArith(i, vm, LUA_OPSUB) }
func mul(i Instruction, vm LuaVM)  { _binaryArith(i, vm, LUA_OPMUL) }
func mod(i Instruction, vm LuaVM)  { _binaryArith(i, vm, LUA_OPMOD) }
func _pow(i Instruction, vm LuaVM)  { _binaryArith(i, vm, LUA_OPPOW) }
func _div(i Instruction, vm LuaVM)  { _binaryArith(i, vm, LUA_OPDIV) }
func idiv(i Instruction, vm LuaVM) { _binaryArith(i, vm, LUA_OPIDIV) }
func _band(i Instruction, vm LuaVM) { _binaryArith(i, vm, LUA_OPBAND) }
func _bor(i Instruction, vm LuaVM)  { _binaryArith(i, vm, LUA_OPBOR) }
func _bxor(i Instruction, vm LuaVM) { _binaryArith(i, vm, LUA_OPBXOR) }
func _shl(i Instruction, vm LuaVM)  { _binaryArith(i, vm, LUA_OPSHL) }
func _shr(i Instruction, vm LuaVM)  { _binaryArith(i, vm, LUA_OPSHR) }
func unm(i Instruction, vm LuaVM)  { _unaryArith(i, vm, LUA_OPUNM) }
func _bnot(i Instruction, vm LuaVM) { _unaryArith(i, vm, LUA_OPBNOT) }

func _len(i Instruction, vm LuaVM) {
	a, b, _ := i.ABC()
	a += 1
	b += 1
	vm.Len(b)
	vm.Replace(a)
}

/**
b,c 起止索引来 concat 放到 a 里
*/
func concat(i Instruction, vm LuaVM) {
	a, b, c := i.ABC()
	a = a + 1
	b = b + 1
	c = c + 1
	for i := b; i <= c; i++ {
		vm.PushValue(i)
	}
	vm.Concat(c - b + 1)
	vm.Replace(a)
}

func _compare(i Instruction, vm LuaVM, op CompareOp) {
	a, b, c := i.ABC()
	vm.GetRK(b)
	vm.GetRK(c)
	if vm.Compare(-2, -1, op) != (a != 0) {
		vm.AddPC(1)
	}
	vm.Pop(2)
}

func eq(i Instruction, vm LuaVM) {
	_compare(i, vm, LUA_OPEQ)
}
func lt(i Instruction, vm LuaVM) {
	_compare(i, vm, LUA_OPLT)
}
func le(i Instruction, vm LuaVM) {
	_compare(i, vm, LUA_OPLE)
}

func not(i Instruction, vm LuaVM) {
	a, b, _ := i.ABC()
	a += 1
	b += 1
	vm.PushBoolean(!vm.ToBoolean(b))
	vm.Replace(a)
}

func testSet(i Instruction, vm LuaVM) {
	a, b, c := i.ABC()
	a += 1
	b += 1
	if vm.ToBoolean(b) == (c != 0) {
		vm.Copy(b, a)
	} else {
		vm.AddPC(1)
	}
}

func test(i Instruction, vm LuaVM) {
	a, _, c := i.ABC()
	a = a + 1
	if vm.ToBoolean(a) != (c != 0) {
		vm.AddPC(1)
	}
}

func forPrep(i Instruction, vm LuaVM) {
	a, sBx := i.AsBx()
	a += 1
	// R(A)-R(A+2), index = index-step
	vm.PushValue(a)
	vm.PushValue(a + 2)
	vm.Arith(LUA_OPSUB)
	vm.Replace(a)

	vm.AddPC(sBx)
}

/**
todo-xxd 这里不理解
*/
func forLoop(i Instruction, vm LuaVM) {
	a, sBx := i.AsBx()
	a += 1
	//index = index + step
	vm.PushValue(a + 2)
	vm.PushValue(a)
	vm.Arith(LUA_OPADD)
	vm.Replace(a)

	stepFlag := vm.ToNumber(a+2) >= 0
	if stepFlag && vm.Compare(a, a+1, LUA_OPLE) ||
		(!stepFlag && vm.Compare(a+1, a, LUA_OPLE)) {
		vm.AddPC(sBx)
		vm.Copy(a, a+3)
	}
}
